/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
    constructor(executor) {
        // 利用try catch捕获异常
        try {
            executor(this.resolve, this.reject)
        }
        catch (e) {
            this.reject(e)
        }
    }
    // promise状态
    status = PENDING;
    //成功之后的值
    value = undefined;
    //失败之后的原因
    reason = undefined;
    // 成功回调用数组存储值
    successCallBack = [];
    // 失败回调用数组存储值
    failCallBack = [];
    resolve = value => {
        //如果状态不是等待，阻止往下执行
        if (this.status !== PENDING) return
        // promise状态改为成功
        this.status = FULFILLED
        //保存成功之后得到值
        this.value = value
        // 判断成功回调是否存在，如果存在 调用
        // this.successCallBack && this.successCallBack(value)
        // while (this.successCallBack.length) this.successCallBack.shift()(value)
        // 这里不需要传值了
        while (this.successCallBack.length) this.successCallBack.shift()()
    }

    reject = reason => {
        //如果状态不是等待，阻止往下执行
        if (this.status !== PENDING) return
        // promise状态改为失败
        this.status = REJECTED
        //保存失败之后得到原因
        this.reason = reason
        // 判断失败回调是否存在，如果存在 调用
        // this.failCallBack && this.failCallBack(value)
        // while (this.failCallBack.length) this.failCallBack.shift()(reason)
        // 这里不需要传值了
        while (this.failCallBack.length) this.failCallBack.shift()()
    }
    then(successCallBack, failCallBack) {
        // 处理传参情况 参数可选
        successCallBack = successCallBack ? successCallBack : value => value
        failCallBack= failCallBack ? failCallBack : reason => { throw reason }
        // 要实现then方法链式调用，先创建一个Promise对象
        let Promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                // 因为拿不到Promise2,所以将他变成一个异步操作去获取
                setTimeout(() => {
                    try {
                        let x = successCallBack(this.value)
                        //    resolve(x)
                        resolvePromise(Promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else if (this.status === REJECTED) {
                //  reject处理逻辑跟resolve大致一样
                setTimeout(() => {
                    try {
                        let x = failCallBack(this.reason)
                        //    resolve(x)
                        resolvePromise(Promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else {
                //等待
                // 将成功回调和失败回调存储
                // this.successCallBack.push(successCallBack)
                // this.failCallBack.push(failCallBack)
                // 这里不能单纯的返回回调函数，而是要将对应的执行方法传过去
                this.successCallBack.push(() => {
                    setTimeout(() => {
                      try {
                        let x = successCallBack(this.value);
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值 直接调用resolve 
                        // 如果是promise对象 查看promsie对象返回的结果 
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promsie2, x, resolve, reject)
                      }catch (e) {
                        reject(e);
                      }
                    }, 0)
                  });
                  this.failCallBack.push(() => {
                    setTimeout(() => {
                      try {
                        let x = failCallBack(this.reason);
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值 直接调用resolve 
                        // 如果是promise对象 查看promsie对象返回的结果 
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promsie2, x, resolve, reject)
                      }catch (e) {
                        reject(e);
                      }
                    }, 0)
                  });
            }
        })
        return Promise2
    }

    finally(callBack){
        // 传入一个回调函数，作为调用时的返回函数
        // 因为finally方法可以链式调用then方法，所以它返回了一个Promise对象
        // 在finally回调函数中可以return 一个值，所以我们这里要利用resolve处理这个对象并return，方便后续then()调用
       return this.then((value)=>{
        return MyPromise.resolve(callBack()).then(()=>value)
            // callBack()
            // // value是Promise对象，直接return
            // return value
        },(reason)=>{
            return  MyPromise.resolve(callBack()).then(()=>{throw reason})
            // callBack()
            // // reject时直接throw
            // throw reason
        })
    }

    // catch 方法实现思路 在catch方法的内部去调用then方法，在调用then方法的成功回调传入undefind,在失败的地方传入回调函数
    catch (failCallback) {
    return this.then(undefined, failCallback)
  }
    // MyPromise中的 all方法是来处理异步并发问题的；
    // 它允许我们按照异步代码调用的顺序来得到异步代码执行的结果
    // 由于all()是一个静态方法
    // all()接受一个数组，返回一个Promise对象
    // 在Promise对象去循环传递进来的数组array
    // 在循环过程中判断当前值是普通值还是Promise对象
    // 如果是Promise对象，先去执行这个Promise对象，
    // 1.执行结果为成功就调用addData()将其加入result数组中，
    // 2.如果状态是失败的，就直接reject让all()状态直接置为失败
    // 因为for循环是瞬间执行完成的，如果for循环中存在了异步操作，得等到result获取晚所有值之后才resolve()
    // 为了解决这个问题用index判断是否执行完所有异步操作
    static all(array) {
        let result = []
        let index = 0
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value
                // 用index来判断result结果数组获取完了没有（异步方法获取为空值的问题）
                index++
                if (index === array.length) {
                    resolve(result)
                }
            }
            // 循环处理all()传过来的参数
            for (let i = 0; i < array.length; i++) {
                const current = array[i];
                // 判断传过来的参数是普通值还是Promise对象
                if (current instanceof MyPromise) {co
                    // Promise对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    //普通值
                    addData(i, current)
                }
            }

        })
    }
    static resolve(value){
        // 判断value是否为Promise对象，如果是直接返回
        if(value instanceof MyPromise){
            return value
        }else{
            // 不是则创建一个Promised对象，再resolve
            return new Promise(resolve=>resolve(value))
        }
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    // 如果返回的是他本身
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) {
        //Promise对象
        // x.then((value)=>resolve(value),reason=>reject(reason))
        x.then(resolve, reject)

    } else {
        // 普通值
        resolve(x)

    }
}
module.exports = MyPromise